// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

const { CardFactory } = require('botbuilder');
const { DialogTurnStatus, WaterfallDialog, WaterfallStepContext } = require('botbuilder-dialogs');
const { QnAMaker } = require('botbuilder-ai');
const { ActiveLearningHelper } = require('./activeLearningHelper');

class DialogHelper {
       
    /**
     * QnAMaker Active Learning Dialog helper class.
     * @param {QnAMakerEndpoint} endpoint An instance of QnAMaker Endpoint.
     */
    constructor(endpoint) {
        this.activeLearningDialogName = "active-learning-dialog";
        this.qnaData = "value-qnaData";
        this.currentQuery = "value-current-query";

        this.qnaMaker = new QnAMaker(endpoint);
        this.activeLearningHelper = new ActiveLearningHelper();
        this.qnaMakerActiveLearningDialog = new WaterfallDialog(this.activeLearningDialogName);
        
        this.qnaMakerActiveLearningDialog
            .addStep(this.callGenerateAnswer.bind(this))
            .addStep(this.filterLowVariationScoreList.bind(this))
            .addStep(this.callTrain.bind(this))
            .addStep(this.displayQnAResult.bind(this));
    }

    /**
    * @param {WaterfallStepContext} stepContext contextual information for the current step being executed.
    */
    async callGenerateAnswer(stepContext){

        // Default QnAMakerOptions
        var qnaMakerOptions = {
            ScoreThreshold: 0.03,
            Top: 3
        };

        if(stepContext.activeDialog.state["options"] != null){
            qnaMakerOptions = stepContext.activeDialog.state["options"];
        }      

        // Perform a call to the QnA Maker service to retrieve matching Question and Answer pairs.
        var qnaResults = await this.qnaMaker.getAnswers(stepContext.context, qnaMakerOptions);

        var filteredResponses = qnaResults.filter(r => r.score > qnaMakerOptions.ScoreThreshold);

        stepContext.values[this.qnaData] = filteredResponses;
        stepContext.values[this.currentQuery] = stepContext.context.activity.text;

        return await stepContext.next();

    }
    
    /**
    * @param {WaterfallStepContext} stepContext contextual information for the current step being executed.
    */
    async filterLowVariationScoreList(stepContext){

        var responses = stepContext.values[this.qnaData];
        
        var filteredResponses = this.activeLearningHelper.getLowScoreVariation(responses);

        stepContext.values[this.qnaData] = filteredResponses;

        if(filteredResponses.length > 1){
            var suggestedQuestions = [];
            filteredResponses.forEach(element => {
                suggestedQuestions.push(element.questions[0]);
            });
            
            var message = GetHeroCard(suggestedQuestions);

            await stepContext.context.sendActivity(message);

            return { status: DialogTurnStatus.waiting };
        }
        else{

            return await stepContext.next(responses);
        }
    }
    
    /**
    * @param {WaterfallStepContext} stepContext contextual information for the current step being executed.
    */
    async callTrain(stepContext){

        var trainResponses = stepContext.values[this.qnaData];
        var currentQuery = stepContext.values[this.currentQuery];

        if(trainResponses.length > 1){
            var reply = stepContext.context.activity.text;
            var qnaResults = trainResponses.filter(r => r.questions[0] == reply);

            if(qnaResults.length > 0){

                stepContext.values[this.qnaData] = qnaResults;

                var feedbackRecords = {
                    FeedbackRecords:[
                        {
                            UserId:stepContext.context.activity.id,
                            UserQuestion: currentQuery,
                            QnaId: qnaResults[0].id
                        }
                    ]
                };

                // Call Active Learning Train API
                this.activeLearningHelper.callTrain(this.qnaMaker.endpoint.host, feedbackRecords, this.qnaMaker.endpoint.knowledgeBaseId, this.qnaMaker.endpoint.endpointKey);
                
                return await stepContext.next(qnaResults);
            }
            else{

                return await stepContext.endDialog();
            }
        }

        return await stepContext.next(stepContext.result);
    }
    
    /**
    * @param {WaterfallStepContext} stepContext contextual information for the current step being executed.
    */
    async displayQnAResult(stepContext) {

        var responses = stepContext.result;
        var message = "No QnAMaker answers found."
        
        if(responses != null){
            if(responses.length > 0){
                message = responses[0].answer;
            }
        }

        await stepContext.context.sendActivity(message);
        return await stepContext.endDialog();
    }
}

/**
* Get Hero card to get user feedback
* @param {Array} suggestionList A list of suggested questions strings.
* @param {string} cardTitle Title of the card.
* @param {string} cardNoMatchText No match text.
*/
function GetHeroCard(suggestionList, cardTitle = "Did you mean:", cardNoMatchText = "None of the above."){

    var cardActions = [];
    suggestionList.forEach(element => {
        cardActions.push({
            value: element,
            type: "imBack",
            title: element
        });
    });
    
    cardActions.push({
        value: cardNoMatchText,
        type: "imBack",
        title: cardNoMatchText
    });
    
    var heroCard = CardFactory.heroCard(
        cardTitle,
        [],
        CardFactory.actions(cardActions));
       
    return  { attachments: [heroCard] }
}

module.exports.DialogHelper = DialogHelper;